import 'reflect-metadata'

interface ModuleMetadata {
  controllers?: Function[]
  providers?: any[]
  imports?: any[] // 可以导入模块 把导入的模块中的 exports 中的提供者或模块导入的模块给自己使用
  exports?: any[] // 模块的导出 可以导出 imports 中的模块 也可以导出自己的提供者
}

/**
 * 工厂 返回一个类装饰器\
 * 用于标识一个类是模块
 */
export function Module(metadata: ModuleMetadata) {
  /**
   * 给模块类添加元数据\
   * 类装饰器 target 是类本身 
   */
  return (target: Function) => {
    // 给模块类添加一个 isModule 元数据 值为 true 标识当前类是一个模块类
    Reflect.defineMetadata('isModule', true, target)

    // 给模块类添加一个 controllers 元数据 值是 metadata.controllers 控制器类组成的数组
    Reflect.defineMetadata('controllers', metadata.controllers, target)
    defineModule(target, metadata.controllers) // 每个控制器类通过 nestModule 元数据关联相应的模块类

    // 给模块类添加一个 providers 元数据 值是 metadata.providers 提供者组成的数组
    Reflect.defineMetadata('providers', metadata.providers, target)
    // 类提供者 通过 nestModule 元数据 关联到 模块类
    defineModule(target,
      (metadata.providers ?? []).map(p => {
        return p instanceof Function ? p : p.useClass
      }).filter(Boolean) // 只保底类提供者 classService 或 { provide: token_service, useClass: classService2 }
    ) 

    // 给模块类添加一个 imports 元数据 值是 metadata.imports 导入的模块组成的数组
    Reflect.defineMetadata('imports', metadata.imports, target)

    // 给模块类添加一个 exports 元数据 值是 metadata.exports 导出的模块或提供者组成的数组
    Reflect.defineMetadata('exports', metadata.exports, target)
  }
}

// 每个控制器 每个提供者都对应的一个 模块类
export function defineModule(nestModule, targets = []) {
  // targets 数组可能是一个控制器类组成的数组
  // targets 数组可能是一个提供者组成的数组
  // nestModule 是 targets 相关联的模块类
  // 添加 nestModule 元数据 用于模块提供者的作用域隔离
  targets.forEach(target => {
    Reflect.defineMetadata('nestModule', nestModule, target)
  })
}

export function Global() {
  return (target: Function) => {
    // 给模块类添加了一个 global 元数据 值是true
    // 代表当前模块类是一个全局模块
    Reflect.defineMetadata('global', true, target)
  }
}

/**
 * 动态模块接口
 */
export interface DynamicModule extends ModuleMetadata {
  module: Function // 动态模块必须的参数 值是模块类
}
